﻿using DeHeng_Mes.Constant;
using DeHeng_Mes.Dao;
using DeHeng_Mes.Dao.PlcDao;
using DeHeng_Mes.Model;
using DeHeng_Mes.Model.Boss;
using DeHeng_Mes.Model.ConfigModel;
using DeHeng_Mes.Model.OrderSingleton;
using DeHeng_Mes.Model.PlcModel;
using DeHeng_Mes.Model.PlcModel.door_01;
using DeHeng_Mes.Model.ProductionSingleton;
using DeHeng_Mes.Model.Singleton;
using DeHeng_Mes.Model.Table;
using DeHeng_Mes.PlcService;
using DeHeng_Mes.Service;
using DeHeng_Mes.Utils;
using Google.Protobuf;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using NPOI.SS.Formula.Eval;
using NPOI.SS.Formula.Functions;
using Org.BouncyCastle.Tls;
using Org.BouncyCastle.Utilities;
using S7.Net;
using SqlSugar;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management;
using System.Net.Http;
using System.Runtime.InteropServices.ComTypes;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.UI;
using System.Xml.Linq;
using W03_UI.Model;
using ZstdSharp.Unsafe;
using MappingTable = DeHeng_Mes.Utils.MappingTable;

namespace DeHeng_Mes.Thread
{
    public class LinePlcToMes
    {
        #region 成员实例
        OrderDao orderDao = new OrderDao();
        PlcDao plcDao = new PlcDao();
        EntranceService entranceService = new EntranceService();
        ExitService exitService = new ExitService();
        VerificationService verificationService = new VerificationService();
        SpotCheakService spotCheakService = new SpotCheakService();
        ErrorType errortype = new ErrorType();
        #endregion

        /// <summary>
        /// 处理读取完成的信号，将追溯码与订单、节拍等信息绑定
        /// </summary>
        /// <param name="types">数据类型字典</param>
        /// <param name="orderModel">工单模型</param>
        public void ProcessOkStatus(Dictionary<object, Type> types, PlcOrderConfigModel orderModel)
        {
            try
            {
                (byte[] bytes, List<string> stationList) = Tools.GetStatusBytes(orderModel);

                if (bytes == null && stationList == null)
                    return;

                int index = 0;

                foreach (var station in stationList)
                {

                    Stopwatch stopwatch = Stopwatch.StartNew();
                    // 获取当前工位的工艺
                    string operationName = MappingTable.GetOperationNo(orderModel.PlcName, station);

                    /*       if (station.Equals(SystemConstant.OP100L))
                           {

                           }*/

                    try
                    {
                        // 获取旧状态值
                        int oldStatus = orderModel.stationStatus[station];

                        // 获取新状态值
                        int newStatus = S7.Net.Types.Int.FromByteArray(bytes.Skip(index * 50 + 2).Take(2).ToArray());

                        if (newStatus != 0 && newStatus != oldStatus)
                        {
                            // 重置状态位
                            orderModel.stationStatus[station] = newStatus;

                            // 初始化反馈结果
                            int isOk = 0;

                            // 初始化循环标识
                            bool isFail = false;

                            // 初始化报警码
                            List<int> errorCodes = new List<int>();

                            string operation = MappingTable.GetOperationId(station);

                            // 获取当前操作类型
                            int typeIndex = S7.Net.Types.Int.FromByteArray(bytes.Skip(index * 50).Take(2).ToArray());


                            // 获取二维码
                            List<string> codes = GetCode(types, station, orderModel);

                            string typeString = string.Empty;

                            switch (typeIndex)
                            {
                                case 1:
                                    typeString = "校验";
                                    break;
                                case 2:
                                    typeString = "入站";
                                    break;
                                case 3:
                                    typeString = "出站";
                                    break;
                                case 4:
                                    typeString = "点检";
                                    break;
                                case 5:
                                    typeString = "补序";
                                    break;
                                case 6:
                                    typeString = "结束时间增补";
                                    break;
                                default:
                                    typeString = "未知";
                                    break;
                            }

                            string codeString = !(codes?.Count > 0) ? "为空" : string.Join(",", codes);

                            Tools.ProduceLogTextError($"[{station}]触发[{typeString}]状态，关联码[{codeString}]，触发标识[{newStatus}]，历史缓存标识[{oldStatus}]");

                            /*// 需要等待模式获取之后去做二维码数量校验
                            if (typeIndex == 2 || typeIndex == 3 || typeIndex == 4)
                                // 校验二维码数量
                                (isOk, isFail, errorCodes) = CodeIsOk(codes, typeString, station, types, orderModel);*/

                            try
                            {
                                if (isFail)
                                    continue;


                                // 1:校验 2:入站 3:出站
                                switch (typeIndex)
                                {
                                    case 1:
                                        // 执行校验
                                        (isOk, errorCodes) = verificationService.CodeVerification(station, codes, stationList);

                                        // 校验成功 执行备份
                                        // orderDao.BackUpCode(codes, station);
                                        break;
                                    case 2:
                                        // 执行入站
                                        (isOk, errorCodes) = entranceService.StationEntrance(station, codes, operation);

                                        if (!string.IsNullOrEmpty(operationName) && operationName.Equals("CNC"))
                                        {
                                            Task.Run(() =>
                                            {
                                                Tools.ProduceLogTextError($"[{station}]执行CNC读取！！！！！！");

                                                // 获取当前工艺数据数组
                                                Tuple<int, int> tuple = MappingTable.GetBytesOff(orderModel.PlcName + "-" + operationName);

                                                byte[] cncBytes = null;

                                                if (tuple != null)
                                                {
                                                    cncBytes = orderModel.plc.ReadBytes(DataType.DataBlock, tuple.Item1, 0, tuple.Item2);
                                                }

                                                SaveCNCData(codes.FirstOrDefault(), station, cncBytes, orderModel, index);
                                            });
                                        }
                                        break;
                                    case 3:
                                        // 执行出站
                                        (isOk, errorCodes) = exitService.StationExit(station, index, bytes, codes, operation, orderModel);
                                        break;
                                    case 4:
                                        // 执行点检
                                        (isOk, errorCodes) = spotCheakService.StationSpotChackSave(station, index, orderModel, plcDao.GetStringFieldValue(types, "Check", station));
                                        break;
                                    case 5:
                                        // 执行补序
                                        (isOk, errorCodes) = errortype.InsertStation(station, codes, orderModel, index);
                                        break;
                                    case 6:
                                        // 执行结束时间增补
                                        (isOk, errorCodes) = errortype.InsertEndStation(station, codes, orderModel, index);
                                        break;
                                }
                            }
                            catch (Exception ex)
                            {
                                isOk = -1;

                                Tools.ProduceLogTextError($"[{typeString}]失败，原因是[{ex.Message}]");
                            }
                            finally
                            {

                                // 反馈类型
                                orderModel.plc.Write(DataType.DataBlock, 5001, index * 50, short.Parse(typeIndex.ToString()));

                                /* var checktypeIndex = (short)orderModel.plc.Read(DataType.DataBlock, 5001, index * 50, VarType.Int, 1);

                                   if (typeIndex != checktypeIndex)
                                   {
                                       Tools.ProduceLogText($"[{station}]写入状态不一致，plc中是[{checktypeIndex}]");
                                       orderModel.plc.Write(DataType.DataBlock, 5001, index * 50, short.Parse(typeIndex.ToString()));
                                   }*/

                                // 反馈结果值
                                orderModel.plc.Write(DataType.DataBlock, 5001, index * 50 + 2, short.Parse(isOk.ToString()));

                                // 反馈报警信息
                                ErrorToPlc(station, index, orderModel.plc, errorCodes, orderModel.PlcName);

                                stopwatch.Stop();

                                long elapsedMilliseconds = stopwatch.ElapsedMilliseconds;

                                Tools.ProduceLogText($"[{station}]本次执行响应耗时[{elapsedMilliseconds}]MS");

                                if (typeIndex == 3)
                                {
                                    // 存储工艺数据
                                    OperationDataSave(station, codes.FirstOrDefault(), orderModel, operationName, operation, codes);
                                }

                                Tools.ProduceLogText($"[{station}]反馈[{typeString}]状态，反馈值[{isOk}]，反馈类型[{typeIndex}]关联码[{codeString}]");
                            }
                        }
                    }
                    finally
                    {
                        index++;
                    }
                }
            }
            catch (Exception ex)
            {
                Tools.ProduceLogTextError($"{orderModel.PlcName}处理读取完成的信号失败，原因是：" + ex.Message);
            }
        }

        /// <summary>
        /// 检测二维码数量
        /// </summary>
        /// <param name="codes"></param>
        /// <param name="typeString"></param>
        /// <param name="station"></param>
        /// <returns></returns>
        private (int, bool, List<int>) CodeIsOk(List<string> codes, string typeString, string station, Dictionary<object, Type> types, PlcOrderConfigModel orderModel)
        {
            if (!(codes?.Count > 0))
            {
                return (2, true, new List<int>()
                {
                    1507
                });
            }

            /*Dictionary<string, object> dictionary = plcDao.GetFieldValues(types, SystemConstant.Code);

            int count = dictionary.Where(x => x.Key.Contains(station)).Count();

            if (orderModel.PlcName.Equals("P1"))
            {
                count = orderModel.plc.ReadBytes(DataType.DataBlock, 5080, 0, 1)[0];

                if (station.Equals(SystemConstant.OP90L) || station.Equals(SystemConstant.OP90R))
                    count = 1;
            }

            if (!(station.Equals(SystemConstant.OP170L) || station.Equals(SystemConstant.OP170R)) && codes.Count != count)
                return (2, true, new List<int>()
                {
                    1508
                });*/

            return (0, false, new List<int>());
        }

        /// <summary>
        /// 报警写入
        /// </summary>
        /// <param name="station"></param>
        /// <param name="index"></param>
        /// <param name="plc"></param>
        /// <param name="errorCodes"></param>
        private void ErrorToPlc(string station, int index, Plc plc, List<int> errorCodes, string plcName)
        {
            if (errorCodes.Count <= 0)
                return;

            // 初始化索引缓存
            Dictionary<int, bool> plcIndex = new Dictionary<int, bool>();

            // 获取Plc信号数组
            Tuple<int, int> byteTuple = MappingTable.GetBytesOff(plcName + "-STATUS");

            byte[] bytes1 = plc.ReadBytes(DataType.DataBlock, 5001, 0, byteTuple.Item2);

            for (int i = 0; i <= 4; i++)
            {
                int nowIndex = i * 2 + (index * 50 + 4);

                int plcErrorCode = S7.Net.Types.Int.FromByteArray(bytes1.Skip(nowIndex).Take(2).ToArray());

                if (plcErrorCode == 0)
                {
                    plcIndex.Add(nowIndex, false);
                }
            }

            foreach (int errorCode in errorCodes)
            {
                int off = plcIndex.Where(x => !x.Value).Select(x => x.Key).FirstOrDefault();

                if (off <= 0)
                    break;

                // 执行报警
                plc.Write(DataType.DataBlock, 5001, off, short.Parse(errorCode.ToString()));

                plcIndex[off] = true;

                Tools.ProduceLogTextError($"[{station}]触发报警[{errorCode}]");
            }
        }

        /// <summary>
        /// 获取二维码
        /// </summary>
        /// <param name="types"></param>
        /// <param name="station"></param>
        /// <returns></returns>
        private List<string> GetCode(Dictionary<object, Type> types, string station, PlcOrderConfigModel orderModel)
        {
            List<string> codes = new List<string>();

            byte modelNum = 0;

            try
            {
                Dictionary<string, object> codeDic = plcDao.GetFieldValues(types, SystemConstant.Code);

                if (station.Equals(SystemConstant.OP90L) || station.Equals(SystemConstant.OP90R))
                {
                    // 初始化模式号
                    modelNum = orderModel.plc.ReadBytes(DataType.DataBlock, 5080, 0, 1)[0];

                    if (modelNum == 1)
                    {
                        codes.Add(codeDic[station].ToString().Trim());

                        return codes;
                    }

                    if (modelNum == 2)
                    {
                        // 获取一号码
                        string codeFirst = codeDic[station].ToString().Trim();

                        bool isSave = ProductionSingleton.Instance.Contains(codeFirst);

                        if (isSave)
                        {
                            // 获取二号码
                            string code = codeDic[station + "_1"].ToString().Trim();

                            // 移除一号码缓存
                            ProductionSingleton.Instance.Remove(codeFirst);

                            codes.Add(code);

                            return codes;
                        }
                        else
                        {
                            // 缓存一号码
                            ProductionSingleton.Instance.Add(codeFirst);

                            codes.Add(codeFirst);

                            return codes;
                        }
                    }
                }

                foreach (var item in codeDic)
                {
                    if (item.Key.Equals(station) || item.Key.Contains(station + "_"))
                    {
                        string code = item.Value.ToString().Trim();

                        if (!string.IsNullOrEmpty(code))
                            codes.Add(code);
                    }
                }
            }
            catch (Exception e)
            {
                Tools.ProduceLogTextError($"[{station}]执行二维码读取失败，原因是{e.Message}");
            }

            return codes;
        }

        /// <summary>
        /// 根据工位判断数据存储类型
        /// </summary>
        /// <param name="station"></param>
        /// <param name="codesReturn"></param>
        /// <param name="bytes"></param>
        private void OperationDataSave(string station, string code, PlcOrderConfigModel orderModel, string operationName, string operation, List<string> traceCodes)
        {
            OrderStatus order = Tools.GetOrder(station, code, orderDao);

            if (string.IsNullOrEmpty(code))
                return;

            // 获取当前工艺数据数组
            Tuple<int, int> tuple = MappingTable.GetBytesOff(orderModel.PlcName + "-" + operationName);

            _ = Task.Run(() =>
            {
                if (tuple != null)
                {
                    byte[] bytes = orderModel.plc.ReadBytes(DataType.DataBlock, tuple.Item1, 0, tuple.Item2);

                    switch (operationName)
                    {
                        case "WELD":
                            SaveWeldData(code, station, bytes, orderModel);
                            break;
                        case "CCD":
                            SaveCCDData(code, station, bytes);
                            break;
                        case "GLUE":
                            SaveGlueData(code, station, bytes);
                            break;
                        case "POINT":
                            SavePointData(code, station, bytes);
                            break;
                    }
                }
                else if (station.Contains("280"))
                {
                    if (order == null)
                        return;

                    string[] codes = code.Split(' ');

                    string traceCode = string.Empty;

                    if (code.Length > 46)
                    {
                        traceCode = $"{codes[0].Substring(codes[0].Length - 6)}{codes[5]}{codes[7]}";
                    }
                    else
                    {
                        traceCode = $"{codes[0].Substring(codes[0].Length - 6)}{codes[4]}{codes[5]}";

                    }

                    // 查询涂胶视觉数据
                    //List<TraceGlueVision> ccdVisionData = orderDao.GetGlueVisionData(traceCode);

                    // 查询焊缝视觉数据
                    List<TraceWeldVision> spotWeldData = orderDao.GetSpotWeldData(traceCode);

                    // 查询FDS数据
                    List<TraceFDS> fdsDataToData = orderDao.GetFdsData(traceCode);

                    // 查询FDS关键数据
                    List<TraceFDSKey> fdsDataDtlToData = orderDao.GetFdsKeyData(traceCode);

                    // 查询拧紧数据
                    Task<string> jsonTask = APIGetData(traceCode);

                    string jsonData = jsonTask.Result;

                    List<ModelContainer> modelContainers = JsonConvert.DeserializeObject<List<ModelContainer>>(jsonData);

                    List<TightenData> tightenDatas = new List<TightenData>();

                    if (modelContainers == null)
                    {
                        Tools.ProduceLogTextError($"[{station}]未查询到拧紧数据，追溯码为[{code}]");

                    }

                    foreach (ModelContainer modelContainer in modelContainers)
                    {
                        TightenData tighten = new TightenData();

                        tighten.Id = modelContainer.Id;

                        tighten.DeviceName = MappingTable.GetDeviceNameFromIp(modelContainer.Model.Controller.Ip);

                        tighten.PSetNumber = modelContainer.Model.PSet.Number.ToString();

                        tighten.TorqueTarget = modelContainer.Model.Results[0].Steps[0].Configuration.torqueTarget.ToString();

                        tighten.FinalTorque = modelContainer.Model.Results[0].Steps[0].Data.FinalTorque.ToString();

                        tighten.FinalAngle = modelContainer.Model.Results[0].Steps[0].Data.FinalAngle.ToString();

                        tighten.ErrorCode = modelContainer.Model.Results[0].Steps[0].Data.errorCode.ToString().Equals("0") ? "OK" : "NG";

                        tighten.StopSource = modelContainer.Model.Results[0].Steps[0].Data.stopSource.ToString();

                        tighten.Code = code;

                        tightenDatas.Add(tighten);
                    }

                    // 数据推送
                    //ViewService.InsertLineMesData(code, station, ccdVisionData);

                    ViewService.InsertLineMesData(code, station, spotWeldData);

                    ViewService.InsertLineMesData(code, station, fdsDataToData);

                    ViewService.InsertLineMesData(code, station, fdsDataDtlToData);

                    ViewService.InsertLineMesData(code, station, tightenDatas);
                }

                if (order == null)
                    return;

                if (station.Equals("R1") || station.Equals("R2") || station.Equals("R3") || station.Equals("R4") || station.Equals("R5"))
                {
                    traceCodes.ForEach(x => PartAndStationPush(station, x, order));
                }
                else
                {
                    PartAndStationPush(station, code, order);
                    // 推送组成关系
                    if (traceCodes.Count > 1)
                        ViewService.InsertDtl(traceCodes, station, operation, code ,order);
                }
            });
        }

        private void PartAndStationPush(string station, string code ,OrderStatus order)
        {
            // 推送单件绑定
            ViewService.CodeBandingOrder(station, code);

            List<PartProcess> partProcesses = orderDao.GetProcessDataByTraceId(code);

            if (partProcesses?.Count > 0)
            {
                PartProcess partProcess = partProcesses.Where(x => x.Station == station).OrderByDescending(x => x.EndTime).FirstOrDefault();

                // 推送过站数据
                ViewService.CodeBandingStationPush(partProcess , order);
            }
        }

        /// <summary>
        /// 调用接口获取拧紧数据
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public async Task<string> APIGetData(string code)
        {
            string jsonData = string.Empty;

            // 创建 HttpClient 实例
            using (HttpClient client = new HttpClient())
            {
                // 创建请求的基础地址
                var baseUrl = "http://localhost:20080/getdata/v1/tighteningresults";

                // 创建查询字符串
                var queryString = $"?vin={code}&includeCurve=true&includeSteps=false";

                // 构造完整的请求 URL
                var requestUrl = baseUrl + queryString;

                // 发送 GET 请求并获取响应
                var response = await client.GetAsync(requestUrl).ConfigureAwait(false);

                // 确保响应成功
                if (response.IsSuccessStatusCode)
                {
                    // 读取响应内容
                    jsonData = await response.Content.ReadAsStringAsync();
                }

            }

            return jsonData;
        }

        /// <summary>
        /// 采集打刻数据
        /// </summary>
        /// <param name="code"></param>
        /// <param name="station"></param>
        /// <param name="bytes"></param>
        private void SavePointData(string code, string station, byte[] bytes)
        {
            string pointCode = S7.Net.Types.String.FromByteArray(bytes.Skip(station[station.Length - 1].ToString().Equals("L") ? 188 : 440).Take(64).ToArray());

            pointCode = pointCode.Trim();

            int v = orderDao.InsertPointCode(code, pointCode, station);

            if (v > 0)
                Tools.ProduceLogText($"[{station}]存储了一条打码数据，追溯码[{code}]，明码[{pointCode}]，ID[{v}]");
        }

        /// <summary>
        /// 采集涂胶数据
        /// </summary>
        /// <param name="station"></param>
        /// <param name="bytes"></param>
        private void SaveGlueData(string code, string station, byte[] bytes)
        {
            try
            {
                // 获取工艺数据
                List<TraceGlue> traceGlues = GetGlueDataList(station, bytes, code);

                if (traceGlues?.Count > 0)
                {
                    bool isSave = orderDao.GlueDataSave(traceGlues, code);

                    if (isSave)
                        Tools.ProduceLogText($"[{station}]成功存储{traceGlues.Count}条涂胶数据，追溯码[{code}]");

                    //推送涂胶工艺数据
                    _ = Task.Run(() => { ViewService.InsertLineMesData(code, station, traceGlues); });
                }
            }
            catch (Exception ex)
            {
                Tools.ProduceLogTextError($"存储涂胶数据失败，原因是{ex.Message}");
            }
        }

        /// <summary>
        /// 采集涂胶数据
        /// </summary>
        /// <param name="station"></param>
        /// <param name="bytes"></param>
        /// <returns></returns>
        private List<TraceGlue> GetGlueDataList(string station, byte[] bytes, string code)
        {
            try
            {
                // 初始化Glue集合
                List<TraceGlue> traceGlues = new List<TraceGlue>();

                Dictionary<string, int> dic = MappingTable.GetGlueOff(station);

                if (dic != null)
                {
                    for (int i = 0; i < dic["Off"]; i++)
                    {
                        TraceGlue traceGlue = new TraceGlue();

                        traceGlue.TraceId = code;
                        traceGlue.Station = station;
                        traceGlue.RangeNo = S7.Net.Types.Int.FromByteArray(bytes.Skip(dic["RangeNo"] + 34 * i).Take(2).ToArray()).ToString();
                        traceGlue.StartTime = S7.Net.Types.DateTime.FromByteArray(bytes.Skip(dic["StartTime"] + 34 * i).Take(8).ToArray()).ToString();
                        traceGlue.EndTime = S7.Net.Types.DateTime.FromByteArray(bytes.Skip(dic["EndTime"] + 34 * i).Take(8).ToArray()).ToString();
                        traceGlue.Press = S7.Net.Types.Real.FromByteArray(bytes.Skip(dic["Press"] + 34 * i).Take(4).ToArray()).ToString();
                        traceGlue.Speed = S7.Net.Types.Real.FromByteArray(bytes.Skip(dic["Speed"] + 34 * i).Take(4).ToArray()).ToString();
                        traceGlue.Amount = S7.Net.Types.Real.FromByteArray(bytes.Skip(dic["Amount"] + 34 * i).Take(4).ToArray()).ToString();
                        traceGlue.Temperature = S7.Net.Types.Real.FromByteArray(bytes.Skip(dic["Temperature"] + 34 * i).Take(4).ToArray()).ToString();

                        traceGlues.Add(traceGlue);
                    }
                }

                return traceGlues;
            }
            catch (Exception ex)
            {
                Tools.ProduceLogTextError($"采集{station}工位涂胶数据失败，原因是：{ex.Message}");
            }

            return null;
        }

        /// <summary>
        /// 存储CCD数据
        /// </summary>
        /// <param name="codesReturn"></param>
        /// <param name="station"></param>
        /// <param name="bytes"></param>
        /// <param name="operation"></param>
        private void SaveCCDData(string code, string station, byte[] bytes)
        {
            // 获取工艺数据
            List<TraceCCD> traceCCDs = GetCCDDataList(station, bytes, code);

            if (traceCCDs?.Count > 0)
            {
                bool isSave = orderDao.CCDDataSave(traceCCDs, code);

                if (isSave)
                    Tools.ProduceLogText($"[{station}]成功存储{traceCCDs.Count}条CCD数据，追溯码[{code}]");

                //推送CCD工艺数据
                _ = Task.Run(() => { ViewService.InsertLineMesData(code, station, traceCCDs); });
            }
        }

        /// <summary>
        /// 获取CCD数据
        /// </summary>
        /// <param name="station"></param>
        /// <returns></returns>
        private List<TraceCCD> GetCCDDataList(string station, byte[] bytes, string code)
        {
            try
            {
                // 初始化CCD集合
                List<TraceCCD> traceCCDs = new List<TraceCCD>();

                Dictionary<string, int> dic = MappingTable.GetCCDOff(station);

                if (dic == null)
                    return null;

                for (int i = 0; i < dic["Off"]; i++)
                {
                    TraceCCD data = new TraceCCD();

                    data.TraceId = code;
                    data.CreateTime = DateTime.Now;
                    data.Station = station;

                    byte[] bytes1 = bytes.Skip(dic["Number"] + (i * 34)).Take(30).ToArray();

                    data.Number = Encoding.ASCII.GetString(bytes1, 2, bytes1[1]);

                    data.Result = S7.Net.Types.Byte.FromByteArray(bytes.Skip(dic["Result"] + (i * 34)).Take(1).ToArray()).ToString();

                    traceCCDs.Add(data);
                }

                return traceCCDs;
            }
            catch (Exception ex)
            {
                Tools.ProduceLogTextError($"[{station}]读取ccd发生异常[{ex.Message}]");
                return null;
            }


        }

        /// <summary>
        /// 存储CNC数据
        /// </summary>
        /// <param name="codesReturn"></param>
        /// <param name="station"></param>
        /// <param name="bytes"></param>
        /// <param name="operation"></param>
        private async void SaveCNCData(string code, string station, byte[] cncBytes, PlcOrderConfigModel orderModel, int index)
        {
            if (string.IsNullOrEmpty(code))
                code = "100100100";

            string stationStatus = $"{orderModel.PlcName}-STATUS";

            Tuple<int, int> statusByteTuple = MappingTable.GetBytesOff(stationStatus);

            // 初始化集合
            List<TraceCnc> traceCncs = new List<TraceCnc>();

            int index1 = 0;

            while (true)
            {
                index1++;
                try
                {
                    // 读取状态数组数据
                    byte[] statusBytes = orderModel.plc.ReadBytes(DataType.DataBlock, statusByteTuple.Item1, SystemConstant.ALL_STARTOFF, statusByteTuple.Item2);

                    int typeIndex = S7.Net.Types.Int.FromByteArray(statusBytes.Skip(index * 50).Take(2).ToArray());

                    if (typeIndex == 3 || index1 > 300)
                    {
                        Tools.ProduceLogTextError($"[{station}]完成CNC读取！！！！！！");

                        // 包装数据
                        if (traceCncs?.Count > 0)
                        {
                            bool isSave = orderDao.CNCDataSave(traceCncs, code);

                            if (isSave)
                                Tools.ProduceLogText($"[{station}]成功存储{traceCncs.Count}条CNC数据，追溯码[{code}]");
                        }

                        return;
                    }

                    // 读取数据
                    byte[] bytes = orderModel.plc.ReadBytes(DataType.DataBlock, 5030, 0, 96);

                    Dictionary<string, int> dic = MappingTable.GetCNCOff(station);

                    if (dic != null)
                    {
                        TraceCnc traceCnc = new TraceCnc();

                        traceCnc.TraceId = code;

                        traceCnc.CNCStatu = Tools.SmallToFloat(bytes.Skip(dic["CNCStatu"]).Take(4).ToArray()).ToString();
                        traceCnc.FeedRate = Tools.SmallToFloat(bytes.Skip(dic["FeedRate"]).Take(4).ToArray()).ToString();
                        traceCnc.ActualValueZ = Tools.SmallToFloat(bytes.Skip(dic["ActualValueZ"]).Take(4).ToArray()).ToString();
                        traceCnc.MainShaftSpeed = Tools.SmallToFloat(bytes.Skip(dic["MainShaftSpeed"]).Take(4).ToArray()).ToString();
                        traceCnc.FirstKnifeCount = Tools.SmallToFloat(bytes.Skip(dic["FirstKnifeCount"]).Take(4).ToArray()).ToString();
                        traceCnc.FirstKnifeLife = Tools.SmallToFloat(bytes.Skip(dic["FirstKnifeLife"]).Take(4).ToArray()).ToString();
                        traceCnc.FirstKnifeWarning = Tools.SmallToFloat(bytes.Skip(dic["FirstKnifeWarning"]).Take(4).ToArray()).ToString();
                        traceCnc.SecondKnifeCount = Tools.SmallToFloat(bytes.Skip(dic["SecondKnifeCount"]).Take(4).ToArray()).ToString();
                        traceCnc.SecondKnifeLife = Tools.SmallToFloat(bytes.Skip(dic["SecondKnifeLife"]).Take(4).ToArray()).ToString();
                        traceCnc.SecondKnifeWarning = Tools.SmallToFloat(bytes.Skip(dic["SecondKnifeWarning"]).Take(4).ToArray()).ToString();
                        //traceCnc.SetPositionZ2 = Tools.SmartConvert(bytes.Skip(dic["SetPositionZ2"]).Take(4).ToArray()).ToString();
                        traceCnc.DepthOfCut = Tools.SmallToFloat(bytes.Skip(dic["DepthOfCut"]).Take(4).ToArray()).ToString();

                        traceCncs.Add(traceCnc);
                    }
                    await Task.Delay(100);
                }
                catch (Exception e)
                {
                    Tools.ProduceLogTextError($"[{station}]执行CNC读取ERROR[{e.Message}]");

                    bool isSave = orderDao.CNCDataSave(traceCncs, code);

                    if (isSave)
                        Tools.ProduceLogText($"[{station}]成功存储{traceCncs.Count}条CNC数据，追溯码[{code}]");

                    return;
                }
            }
        }

        /// <summary>
        /// 存储弧焊数据
        /// </summary>
        /// <param name="station"></param>
        /// <param name="bytes"></param>
        private void SaveWeldData(string code, string station, byte[] bytes, PlcOrderConfigModel orderModel)
        {
            // 获取工艺数据
            List<TraceWeld> weldDatas = GetWeldDataList(bytes, station, code, orderModel);

            // 插入弧焊数据
            if (weldDatas?.Count > 0)
            {
                bool isSave = orderDao.WeldDataSave(weldDatas, code);

                if (isSave)
                    Tools.ProduceLogText($"[{station}]成功存储{weldDatas.Count}条弧焊数据，追溯码[{code}]");

                //推送弧焊工艺数据
                _ = Task.Run(() => { ViewService.InsertLineMesData(code, station, weldDatas); });
            }
        }


        /// <summary>
        /// 获取工艺数据
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        private List<TraceWeld> GetWeldDataList(byte[] bytes, string station, string code, PlcOrderConfigModel orderModel)
        {
            // 初始化集合
            List<TraceWeld> weldDatas = new List<TraceWeld>();

            Dictionary<string, int> dicOff = MappingTable.GetWeldOff(station);

            int jobOff = 0;

            if (orderModel.PlcName.Equals("P2"))
                jobOff = 800;
            else
                jobOff = 1120;

            // 读取job数据
            byte[] jobBytes = orderModel.plc.ReadBytes(DataType.DataBlock, 5002, 0, jobOff);

            if (dicOff == null)
                return null;

            if (dicOff != null)
            {
                for (int i = 0; i < dicOff["Off"]; i++)
                {
                    TraceWeld traceWeld = new TraceWeld();

                    traceWeld.TraceId = code;

                    traceWeld.SeamNo = S7.Net.Types.Int.FromByteArray(bytes.Skip(dicOff["SeamNo"] + 1618 * i).Take(2).ToArray()).ToString();
                    traceWeld.StartTime = S7.Net.Types.DateTime.FromByteArray(bytes.Skip(dicOff["StartTime"] + 1618 * i).Take(8).ToArray()).ToString();
                    traceWeld.EndTime = S7.Net.Types.DateTime.FromByteArray(bytes.Skip(dicOff["EndTime"] + 1618 * i).Take(8).ToArray()).ToString();
                    traceWeld.Station = station;

                    string[] weldI = new string[100];
                    string[] weldU = new string[100];
                    string[] wireSpeed = new string[100];
                    string[] gasFlow = new string[100];
                    string[] job = new string[10];

                    for (int j = 0; j < 100; j++)
                    {
                        weldI[j] = S7.Net.Types.Real.FromByteArray(bytes.Skip(dicOff["WeldI"] + 1618 * i + j * 4).Take(4).ToArray()).ToString();
                        weldU[j] = S7.Net.Types.Real.FromByteArray(bytes.Skip(dicOff["WeldU"] + 1618 * i + j * 4).Take(4).ToArray()).ToString();
                        wireSpeed[j] = S7.Net.Types.Real.FromByteArray(bytes.Skip(dicOff["WireSpeed"] + 1618 * i + j * 4).Take(4).ToArray()).ToString();
                        gasFlow[j] = S7.Net.Types.Real.FromByteArray(bytes.Skip(dicOff["GasFlow"] + 1618 * i + j * 4).Take(4).ToArray()).ToString();

                        if (j < 10)
                        {
                            job[j] = S7.Net.Types.Int.FromByteArray(jobBytes.Skip(dicOff["Job"] + 20 * i + j * 2).Take(2).ToArray()).ToString();
                        }
                    }

                    traceWeld.WeldI = string.Join(",", weldI);
                    traceWeld.WeldU = string.Join(",", weldU);
                    traceWeld.WireSpeed = string.Join(",", wireSpeed);
                    traceWeld.GasFlow = string.Join(",", gasFlow);
                    traceWeld.Job = string.Join(",", job);

                    weldDatas.Add(traceWeld);
                }
            }
            return weldDatas;
        }
    }
}